package cube

import (
	"fmt"
	"shqsoft.cn/pasnj/base"
	"shqsoft.cn/pasnj/bi/datapackage"
	"strings"

	"github.com/go-redis/redis"
)

//Hierarchy 维度层次
type Hierarchy struct {
	redisCli *redis.Client
	setting  *datapackage.Hierarchy
	dim      *Dimension
	lKeys    []string
	hKeys    []string
	sKeys    []string
}

//NewHierarchy 新建维度层次
func newHierarchy(dim *Dimension, hie *datapackage.Hierarchy, dimIndex int, hieIndex int, redisIndex int) *Hierarchy {
	levLen := len(hie.Levels)
	lkeys := make([]string, levLen, levLen)
	hkeys := make([]string, levLen, levLen)
	skeys := make([]string, levLen, levLen)
	for i := 0; i < levLen; i++ {
		lkeys[i] = fmt.Sprintf("d%d:h%d:l:%d", dimIndex, hieIndex, i)
		hkeys[i] = fmt.Sprintf("d%d:h%d:h:%d:", dimIndex, hieIndex, i)
		skeys[i] = fmt.Sprintf("d%d:h%d:s:%d:", dimIndex, hieIndex, i)
	}
	return &Hierarchy{
		redisCli: base.RedisClients[redisIndex],
		lKeys:    lkeys,
		hKeys:    hkeys,
		sKeys:    skeys,
		setting:  hie,
		dim:      dim,
	}
}

//AddData 向层次结构中添加
func (h *Hierarchy) AddData(data map[string]interface{}) error {
	for i, lev := range h.setting.Levels {
		if _, ok := data[h.setting.PrimaryKey]; !ok {
			return fmt.Errorf("配置错误，字段名：%s在表%s中不存在！", h.setting.PrimaryKey, h.setting.Table.Name)
		}
		if _, ok := data[lev.Column]; !ok {
			return fmt.Errorf("配置错误，字段名：%s在表%s中不存在！", lev.Column, h.setting.Table.Name)
		}
		if _, ok := data[lev.NameColumn]; lev.NameColumn != "" && !ok {
			return fmt.Errorf("配置错误，字段名：%s在表%s中不存在！", lev.NameColumn, h.setting.Table.Name)
		}
		if _, ok := data[lev.OrderColumn]; lev.OrderColumn != "" && !ok {
			return fmt.Errorf("配置错误，字段名：%s在表%s中不存在！", lev.OrderColumn, h.setting.Table.Name)
		}
		hk := h.hKeys[i] + base.ToString(data[lev.Column])
		find, err := h.redisCli.Exists(hk).Result()
		if err != nil {
			return fmt.Errorf("构建维度层次时，调用redis命令Exists出错:%s", err)
		}
		if find == 0 {
			levMap := make(map[string]interface{})
			levMap[lev.NameColumn] = data[lev.NameColumn]
			levMap[lev.OrderColumn] = data[lev.OrderColumn]
			for _, prop := range lev.Properties {
				if _, ok := data[prop.Column]; !ok {
					return fmt.Errorf("配置错误，字段名：%s在表%s中不存在！", prop.Column, h.setting.Table.Name)
				}
				levMap[prop.Column] = data[prop.Column]
			}
			if err := h.redisCli.HMSet(hk, levMap).Err(); err != nil {
				return fmt.Errorf("构建维度层次时，调用redis命令HMSet出错:%s", err)
			}
			lk := h.lKeys[i]
			if err := h.redisCli.RPush(lk, data[lev.Column]).Err(); err != nil {
				return fmt.Errorf("构建维度层次时，调用redis命令RPush出错:%s", err)
			}
		}
		if strings.ToLower(h.setting.PrimaryKey) == strings.ToLower(lev.Column) {
			break
		}
		sk := h.sKeys[i] + base.ToString(data[lev.Column])
		nextLevCol := h.setting.Levels[i+1].Column
		if err := h.redisCli.SAdd(sk, data[nextLevCol]).Err(); err != nil {
			return fmt.Errorf("构建维度层次时，调用redis命令SAdd出错:%s", err)
		}
	}
	return nil
}

//Delete 删除维度
func (h *Hierarchy) Delete() error {
	levLen := len(h.setting.Levels)
	for i := 0; i < levLen; i++ {
		if err := h.deleteLevel(i); err != nil {
			return err
		}
	}
	return nil
}

func (h *Hierarchy) deleteLevel(levIndex int) error {
	if err := deleteByList(h.redisCli, h.hKeys[levIndex], h.lKeys[levIndex]); err != nil {
		return err
	}
	if err := deleteByList(h.redisCli, h.sKeys[levIndex], h.lKeys[levIndex]); err != nil {
		return err
	}
	_, err := h.redisCli.Del(h.lKeys[levIndex]).Result()
	if err != nil {
		return fmt.Errorf("删除维度层次时，调用redis命令Del出错:%s", err)
	}
	return nil
}

func (h *Hierarchy) getAllLeafKeys() ([]string, error) {
	levLen := len(h.setting.Levels)
	lkey := h.lKeys[levLen-1]
	count, err := h.redisCli.LLen(lkey).Result()
	if err != nil {
		return nil, err
	}
	return h.redisCli.LRange(lkey, 0, count).Result()
}

//getLeafKeys 根据提供的级别键值，获取层次的叶结点的键值
func (h *Hierarchy) getLeafKeys(levelName string, keys ...string) ([]string, error) {
	index := -1
	levLen := len(h.setting.Levels)
	for i, lev := range h.setting.Levels {
		if lev.Name == levelName {
			index = i
			break
		}
	}
	if index == -1 {
		return nil, fmt.Errorf("指定的级别%s在层次%s中不存在", levelName, h.setting.Name)
	}
	oldKeys := keys
	for index < levLen-1 {
		newKeys := make([]string, 0)
		for _, okey := range oldKeys {
			sk := h.sKeys[index]
			sk = sk + okey
			skeys, err := h.redisCli.SMembers(sk).Result()
			if err != nil {
				return nil, fmt.Errorf("获取层次级别的主键值时，调用redis命令SMembers出错:%s", err)
			}
			newKeys = append(newKeys, skeys...)
		}
		oldKeys = newKeys
		index++
	}
	return oldKeys, nil
}

//NewLevel 根据名称创建层级级别
func (h *Hierarchy) NewLevel(levelName string) (*Level, error) {
	for i, lev := range h.setting.Levels {
		if lev.Name == levelName {
			return &Level{
				redisCli: h.redisCli,
				setting:  &lev,
				lKey:     h.lKeys[i],
				hKey:     h.hKeys[i],
				sKey:     h.sKeys[i],
				index:    i,
				hie:      h,
				filters:  make([]filter, 0),
				sorts:    make([]sort, 0),
			}, nil
		}
	}
	return nil, fmt.Errorf("指定的级别%s在层次%s中不存在", levelName, h.setting.Name)
}
